package com.bicntech.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bicntech.common.utils.ObjectUtil;
import com.bicntech.system.entity.InfieldBasicData;
import com.bicntech.system.entity.VehicleRefuelingStatistics;
import com.bicntech.system.service.InfieldBasicDataService;
import com.bicntech.system.service.VehicleRefuelingStatisticsService;
import com.bicntech.system.mapper.VehicleRefuelingStatisticsMapper;
import com.bicntech.system.vo.VehicleRefuelingStatisticsVO;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.Month;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author casc1
 * @description 针对表【vehicle_refueling_statistics(车辆加油统计)】的数据库操作Service实现
 * @createDate 2024-03-09 14:29:22
 */
@Service
public class VehicleRefuelingStatisticsServiceImpl extends ServiceImpl<VehicleRefuelingStatisticsMapper, VehicleRefuelingStatistics>
        implements VehicleRefuelingStatisticsService {

    @Resource
    private InfieldBasicDataService infieldBasicDataService;

    @Override
    public void addRefueling(String wagonNumber, LocalDateTime inspectDate, BigDecimal refuelingVolume) {
        int year = inspectDate.getYear();
        int month = inspectDate.getMonthValue();
        synchronized (wagonNumber.intern()) {
            VehicleRefuelingStatistics refuelingStatistics = Optional.ofNullable(
                            super.lambdaQuery()
                                    .eq(VehicleRefuelingStatistics::getWagonNumber, wagonNumber)
                                    .eq(VehicleRefuelingStatistics::getYear, year)
                                    .eq(VehicleRefuelingStatistics::getMonth, month)
                                    .one()
                    )
                    .filter(ObjectUtil::notEmpty)
                    .map(it -> it.setRefuelingVolume(it.getRefuelingVolume().add(refuelingVolume)))
                    .orElse(new VehicleRefuelingStatistics()
                            .setWagonNumber(wagonNumber)
                            .setYear(year)
                            .setMonth(month)
                            .setRefuelingVolume(refuelingVolume));
            super.saveOrUpdate(refuelingStatistics);

        }
    }

    @Override
    public List<VehicleRefuelingStatisticsVO> annualStatistics(Integer year, String wagonNumber, Integer checklistType) {
        List<VehicleRefuelingStatisticsVO> statisticsVOList = new ArrayList<>();

        Map<String, List<VehicleRefuelingStatistics>> listByWagonNumber = super.lambdaQuery()
                .eq(VehicleRefuelingStatistics::getYear, year)
                .like(StrUtil.isNotBlank(wagonNumber), VehicleRefuelingStatistics::getWagonNumber, wagonNumber)
                .list()
                .stream()
                .collect(Collectors.groupingBy(VehicleRefuelingStatistics::getWagonNumber));

        if (MapUtil.isEmpty(listByWagonNumber)) return Collections.emptyList();
        List<InfieldBasicData> infieldBasicDataList = infieldBasicDataService.list();
        listByWagonNumber.forEach((k, v) -> {
            InfieldBasicData basicByWagonNumber = this.getInfieldBasicByWagonNumber(k, infieldBasicDataList);
            statisticsVOList.add(VehicleRefuelingStatisticsVO
                    .builder()
                    .wagonNumber(k)
                    .fuelChargeList(this.supplement(year, this.toFuelChargeVo(v)))
                    .checklistType(basicByWagonNumber.getType())
                    .applicableModels(basicByWagonNumber.getApplicableModels())
                    .build());
        });


        infieldBasicDataList.forEach(it ->
                Optional.ofNullable(it.getApplicableModelsData())
                        .filter(CollUtil::isNotEmpty)
                        .ifPresent(applicable -> applicable.stream()
                                .distinct()
                                .filter(f -> !listByWagonNumber.containsKey(f))
                                .forEach(a -> statisticsVOList.add(VehicleRefuelingStatisticsVO
                                        .builder()
                                        .wagonNumber(a)
                                        .fuelChargeList(this.supplement(year, new ArrayList<>()))
                                        .checklistType(it.getType())
                                        .applicableModels(it.getApplicableModels())
                                        .build())))
        );


        return statisticsVOList
                .stream()
                .filter(f -> ObjectUtil.isEmptyObject(checklistType) || this.filterByChecklistType(checklistType, f))
                .filter(wagonF -> StrUtil.isBlank(wagonNumber) || this.filterByWagonNumber(wagonNumber, wagonF))
                .sorted(Comparator.comparing(VehicleRefuelingStatisticsVO::getChecklistType))
                .collect(Collectors.toList());
    }

    private boolean filterByChecklistType(Integer checklistType, VehicleRefuelingStatisticsVO statisticsVO) {
        return statisticsVO.getChecklistType().equals(checklistType);
    }

    private boolean filterByWagonNumber(String wagonNumber, VehicleRefuelingStatisticsVO statisticsVO) {
        return StrUtil.contains(statisticsVO.getWagonNumber(), wagonNumber);
    }

    private List<VehicleRefuelingStatisticsVO.FuelCharge> toFuelChargeVo(List<VehicleRefuelingStatistics> list) {
        return ObjectUtil.deepCopyList(list, VehicleRefuelingStatisticsVO.FuelCharge.class);
    }

    private List<VehicleRefuelingStatisticsVO.FuelCharge> supplement(Integer year, List<VehicleRefuelingStatisticsVO.FuelCharge> fuelChargeList) {
        List<Integer> monthList = fuelChargeList.stream()
                .map(VehicleRefuelingStatisticsVO.FuelCharge::getMonth)
                .collect(Collectors.toList());

        for (int i = 1; i <= Month.DECEMBER.getValue(); i++) {
            if (!CollUtil.contains(monthList, i)) {
                fuelChargeList.add(VehicleRefuelingStatisticsVO.FuelCharge
                        .builder()
                        .year(year)
                        .month(i)
                        .refuelingVolume(new BigDecimal("0.0"))
                        .build());
            }
        }
        return fuelChargeList
                .stream()
                .sorted(Comparator.comparing(VehicleRefuelingStatisticsVO.FuelCharge::getMonth))
                .collect(Collectors.toList());
    }

    private InfieldBasicData getInfieldBasicByWagonNumber(String wagonNumber, List<InfieldBasicData> infieldBasicDataList) {
        return infieldBasicDataList
                .stream()
                .filter(f -> CollUtil.contains(f.getApplicableModelsData(), wagonNumber))
                .findFirst()
                .orElseGet(InfieldBasicData::new);
    }

}




